/**
 * 
 */
package platzerworld.kegeln.mannschaft.db;

import java.util.ArrayList;
import java.util.List;

import platzerworld.kegeln.KegelverwaltungDatenbank;
import platzerworld.kegeln.common.KeyValueVO;
import platzerworld.kegeln.common.db.Sortierung;
import platzerworld.kegeln.mannschaft.vo.MannschaftVO;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.util.Log;

/**
 * Der MannschaftSpeicher ist die Schnittstelle zu persistenten Mannschaftsdaten.
 *
 * Die Mannschaftsdaten sind in der Anwendungsdatenbank abgelegt. Die Anwendung sollte nur über 
 * den MannschaftSpeicher auf gespeicherte Mannschaften zugreifen.
 * 
 * Um den MannschaftSpeicher erzeugen zu können, muss die aufrufende Android-Komponente ihren Context übergeben.
 * 
 * @author platzerg
 */
public class MannschaftSpeicher {

	/** Markierung für Logging. */
	private static final String TAG = "SpielerSpeicher";
	
	/** Verweis auf die Kegelverwaltung-Datenbank. */
	private KegelverwaltungDatenbank mDb;

	/**
	 * Erzeugt einen neuen MannschaftSpeicher. 
	 * Dabei wird sichergestellt, dass die zugrundeliegende Datenbank unmittelbar nutzbar ist.
	 * 
	 * @param context Kontext der Anwendung, für die der Speicher gültig sein soll.
	 */
	public MannschaftSpeicher(Context context) {
		mDb = new KegelverwaltungDatenbank(context);
		Log.d(TAG, "MannschaftSpeicher angelegt.");
	}

	/**
	 * Erzeugung ohne Context nicht möglich.
	 */
	private MannschaftSpeicher() {
	}


	/**
	 * Speichert eine Mannschaft. 
	 * Ist dieser bereits in der Datenbank bekannt, wird der vorhandene Datensatz geändert.
	 * Ansonsten wird ein neuer Datensatz erzeugt.
	 * 
	 * @param mannschaftVO  zu speichernde Mannschaft.
	 * @return id der persistenten Klasse.
	 * @throws SQLException falls Neuanlegen gefordert aber nicht möglich.
	 */
	public long speichereMannschaft(MannschaftVO mannschaftVO) {
		if (mannschaftVO.istNeu()) {
			return speichereMannschaftAllColumns(mannschaftVO);
		} else {
			aendereMannschaftAllColumns(mannschaftVO);
			return mannschaftVO.key;
		}
	}
	
	/**
	 * Legt eine neue Mannschaft in der Datenbank an.
	 * 
	 * @param mannschaftVO  zu speichernde Mannschaft.
	 * 
	 * @return Datenbank-Id der neuen Mannschaft
	 * @throws SQLException falls Speichern nicht möglich.
	 */
	public long speichereMannschaftAllColumns(MannschaftVO mannschaftVO) {

		final ContentValues daten = new ContentValues();
		daten.put(MannschaftTbl.NAME, mannschaftVO.name);
		daten.put(MannschaftTbl.MANNSCHAFT,mannschaftVO.mannschaft);
		daten.put(MannschaftTbl.KLASSE_ID, mannschaftVO.klasseId);
		daten.put(MannschaftTbl.VEREIN_ID, mannschaftVO.vereinId);

		final SQLiteDatabase dbCon = mDb.getWritableDatabase();

		try {
			final long id = dbCon.insertOrThrow(MannschaftTbl.TABLE_NAME, null, daten);
			Log.i(TAG, "Klasse mit id=" + id + " erzeugt.");
			return id;
		} finally {
			dbCon.close();
		}
	}

	/**
	 * Ändert eine vorhandene Mannschaft in der Datenbank. Wenn die id nicht mitgegeben wird, wird keine Änderung durchgeführt.
	 * Es werden bei der Änderung alle Parameter berücksichtigt. 
	 * 
	 * @param mannschaftVO  zu speichernde Mannschaft.
	 */
	public void aendereMannschaftAllColumns(MannschaftVO mannschaftVO) {
		if (mannschaftVO.key == 0) {
			Log.w(TAG, "id == 0 => kein update möglich.");
			return;
		}

		final ContentValues daten = new ContentValues();
		daten.put(MannschaftTbl.NAME, mannschaftVO.name);
		daten.put(MannschaftTbl.MANNSCHAFT, mannschaftVO.mannschaft);
		daten.put(MannschaftTbl.KLASSE_ID, mannschaftVO.klasseId);
		daten.put(MannschaftTbl.VEREIN_ID, mannschaftVO.vereinId);

		final SQLiteDatabase dbCon = mDb.getWritableDatabase();

		try {
			dbCon.update(MannschaftTbl.TABLE_NAME, daten, MannschaftTbl.WHERE_ID_EQUALS,
					new String[] { String.valueOf(mannschaftVO.key) });
			Log.i(TAG, "Mannschaft id=" + mannschaftVO.key + " aktualisiert.");
		} finally {
			dbCon.close();
		}
	}

	/**
	 * Entfernt eine Mannschaft aus der Datenbank.
	 * 
	 * @param id Schlüssel der gesuchten Mannschaft
	 * @return true, wenn Datensatz geloescht wurde.
	 */
	public boolean loescheMannschaft(long id) {
		final SQLiteDatabase dbCon = mDb.getWritableDatabase();

		int anzahlLoeschungen = 0;
		try {
			anzahlLoeschungen = dbCon.delete(MannschaftTbl.TABLE_NAME, MannschaftTbl.WHERE_ID_EQUALS,
					new String[] { String.valueOf(id) });
			Log.i(TAG, "Mannschaft id=" + id + " gelöscht.");
		} finally {
			dbCon.close();
		}
		return anzahlLoeschungen == 1;
	}
	
	/**
	 * Entfernt eine Mannschaft aus der Datenbank.
	 * 
	 * @param klasseId Klasse-ID der gesuchten Mannschaft
	 * @return true, wenn Datensatz geloescht wurde.
	 */
	public boolean loescheAlleMannschaftenZurKlasseId(long klasseId) {
		final SQLiteDatabase dbCon = mDb.getWritableDatabase();

		int anzahlLoeschungen = 0;
		try {
			anzahlLoeschungen = dbCon.delete(MannschaftTbl.TABLE_NAME, MannschaftTbl.WHERE_ID_KLASSE_ID_EQUALS,
					new String[] { String.valueOf(klasseId) });
			Log.i(TAG, "Mannschaft klasseId=" + klasseId + " gel�scht.");
		} finally {
			dbCon.close();
		}
		return anzahlLoeschungen == 1;
	}

	/**
	 * Liefert einen Cursor auf alle Felder der Mannschaft-Tabelle zurück.
	 * Wenn eine komplette Mannschaft genutzt werden soll, ist die ladeMannschaft-Methode vorzuziehen.
	 * 
	 * @param id Schlüssel des gesuchten Kontakts
	 * @return Cursor, oder null
	 */
	public Cursor ladeMannschaft(long id) {
		return mDb.getReadableDatabase().query(MannschaftTbl.TABLE_NAME, MannschaftTbl.ALL_COLUMNS,
				MannschaftTbl.WHERE_ID_EQUALS, new String[] { String.valueOf(id) }, null, null, null);
	}

	/**
	 * Liefert ein Value-Object MannschaftVO mit allen Feldern der Mannschaft-Tabelle zurück.
	 * 
	 * @param id Schüssel des gesuchten Kontakts
	 * @return MannschaftVO, oder null
	 */
	public MannschaftVO ladeMannschaftVO(long id) {
		MannschaftVO kontakt = null;
		Cursor c = null;
		try {
			c = mDb.getReadableDatabase().query(MannschaftTbl.TABLE_NAME, MannschaftTbl.ALL_COLUMNS,
					MannschaftTbl.WHERE_ID_EQUALS, new String[] { String.valueOf(id) }, null, null, null);
			if (c.moveToFirst() == false) {
				return null;
			}
			kontakt = ladeGeoKontakt(c);
		} finally {
			if (c != null) {
				c.close();
			}
		}
		return kontakt;
	}

	/**
	 * Liefert einen Cursor auf alle Felder der Mannschaft-Tabelle zurück.
	 * Suchkriterium ist den Namen der Mannschaft.
	 * 
	 * @param name  Name der Mannschaft.
	 * @return Cursor, oder null
	 */
	public Cursor ladeMannschaftDetails(String name) {
		if (name == null) {
			return null;
		}
		return mDb.getReadableDatabase().query(MannschaftTbl.TABLE_NAME, MannschaftTbl.ALL_COLUMNS, MannschaftTbl.WHERE_NAME_EQUALS,
				new String[] { name }, null, null, MannschaftTbl.DEFAULT_SORT_ORDER);
	}

	/**
	 * Liefert alle Mannschaften sortiert nach Name zurück.
	 * 
	 * Es kann (optional) ein Filterkriterium angegeben werden. 
	 * Wenn der namensFilterdefiniert ist, werden nur Kontakte geliefert, deren NAME mit diesem Buchstaben beginnt.
	 * 
	 * @param namensFilter Anfangsbuchstaben (case sensitive) der zu suchenden Mannschaften.
	 * @return Cursor auf die Ergebnisliste.
	 */
	public Cursor ladeMannschaftListe(CharSequence namensFilter) {
		return ladeMannschaftListe(Sortierung.STANDARD, namensFilter);
	}

	/**
	 * Liefert alle Mannschaften zur KlassenId und Namensfilter.
	 * 
	 * @param namensFilter Anfangsbuchstaben (case sensitive) der zu suchenden Kontakte.
     * @param klasseId Anfangsbuchstaben (case sensitive) der zu suchenden Kontakte.
	 * @return Cursor auf die Ergebnisliste.
	 */
	public Cursor ladeMannschaftZurKlasseListe(CharSequence namensFilter, long klasseId) {
		return ladeMannschaftZurKlasseListe(Sortierung.ID, namensFilter, klasseId);
	}
	
	/**
	 * Liefert alle Mannschaften zur KlassenId und Namensfilter.
	 * 
     * @param klasseId Anfangsbuchstaben (case sensitive) der zu suchenden Kontakte.
	 * @return List<KeyValueVO> mannschaften
	 */
	public List<KeyValueVO> ladeAlleMannschaftenZurKlasseListeVO(long klasseId) {
		return ladeMannschaftZurKlasseListeVO(Sortierung.ID, null, klasseId);
	}
	
	/**
	 * Liefert alle Mannschaften zur KlassenId und Namensfilter.
	 * 
	 * @param namensFilter Anfangsbuchstaben (case sensitive) der zu suchenden Kontakte.
     * @param klasseId Anfangsbuchstaben (case sensitive) der zu suchenden Kontakte.
	 * @return List<KeyValueVO> mannschaften
	 */
	public List<KeyValueVO> ladeMannschaftZurKlasseListeVO(CharSequence namensFilter, long klasseId) {
		return ladeMannschaftZurKlasseListeVO(Sortierung.ID, namensFilter, klasseId);
	}
	
	/**
	 * Liefert alle Mannschaften zur KlassenId und mit einstellbarer Sortierung zurück.
	 * 
	 * @param sortierung Art der Sortierung
	 * @param namensFilter Anfangsbuchstaben (case sensitive) der zu suchenden Kontakte.
	 * @param klasseId KlassenId
	 * @return List<KeyValueVO> mannschaften
	 */
	public List<KeyValueVO> ladeMannschaftZurKlasseListeVO(Sortierung sortierung, CharSequence namensFilter, long klasseId) {
		
		SQLiteDatabase d = mDb.getReadableDatabase();
		Cursor mannschaftCursor = d.query(MannschaftTbl.TABLE_NAME, 
				MannschaftTbl.ALL_COLUMNS, 
				MannschaftTbl.KLASSE_ID + "=" + String.valueOf(klasseId), null, null, null, null);
		
		return ladeMannschaftKeyValueVO(mannschaftCursor);
	}
	
	/**
	 * Lädt die Klassen aus dem KlasseTbl-Datensatz, auf dem der Cursor gerade steht.
	 * 
	 * Der Cursor wird anschließend deaktiviert, da er im KlasseSpeicher nur intern als "letzter Aufruf" aufgerufen wird.
	 * 
	 * @param c aktuelle Cursorposition != null
	 * @return ArrayList<KeyValueVO> mannschaften
	 */
	public ArrayList<KeyValueVO> ladeMannschaftKeyValueVO(Cursor c) {	
		ArrayList<KeyValueVO> mannschaftVOs = new ArrayList<KeyValueVO>();
		KeyValueVO mannschaftVO = null;
		if (c != null ) {
    		if  (c.moveToFirst()) {
    			do {    				
    				mannschaftVO= new KeyValueVO(
    						c.getLong(c.getColumnIndex(MannschaftTbl.ID)), 
    						c.getString(c.getColumnIndex(MannschaftTbl.NAME)));
    				
    				mannschaftVOs.add(mannschaftVO);
    			}while (c.moveToNext());
    		} 
    	}

		return mannschaftVOs;
	}
	
	/**
	 * Lädt die Mannschaften aus dem MannschaftTbl-Datensatz, auf dem der Cursor gerade steht.
	 * Der Cursor wird anschließend deaktiviert, da er im Mannschaftpeicher nur intern als "letzter Aufruf" aufgerufen wird.
	 * 
	 * @return List<String[]> mannschaften als String-Array
	 */
	public List<String[]> ladeMannschaftAsStringArray() {
		Cursor c = ladeMannschaftListe(null);
		List<String[]> mannschaftenAsArray = new ArrayList<String[]>();
		
		if (c != null ) {
    		if  (c.moveToFirst()) {
    			do {    	
    				String[] mannschaftZeile = new String[5];
    				//_id, name, klasse_id, verein_id, mannschaft
    				mannschaftZeile[0] = String.valueOf(c.getInt(c.getColumnIndex(MannschaftTbl.ID)));
    				mannschaftZeile[1] = c.getString(c.getColumnIndex(MannschaftTbl.NAME));
    				
    				mannschaftZeile[2] = String.valueOf(c.getInt(c.getColumnIndex(MannschaftTbl.KLASSE_ID)));
    				mannschaftZeile[3] = String.valueOf(c.getInt(c.getColumnIndex(MannschaftTbl.VEREIN_ID)));
    				mannschaftZeile[4] = String.valueOf(c.getInt(c.getColumnIndex(MannschaftTbl.MANNSCHAFT)));
    				mannschaftenAsArray.add(mannschaftZeile);
    			}while (c.moveToNext());
    		} 
    	}

		return mannschaftenAsArray;
	}
	
	/**
	 * Lädt die Mannschaften aus dem MannschaftTbl-Datensatz.
	 * 
	 * @param klasseId KlasseId
	 * @return Exemplar von Klasse.
	 */
	public ArrayList<MannschaftVO> ladeMannschaftenAsString(int klasseId) {	
		SQLiteDatabase d = mDb.getReadableDatabase();
		Cursor c = d.query(MannschaftTbl.TABLE_NAME, 
				MannschaftTbl.ALL_COLUMNS, 
				MannschaftTbl.KLASSE_ID + "=" + String.valueOf(klasseId), null, null, null, null);
		
		ArrayList<MannschaftVO> mannschaftListe = new ArrayList<MannschaftVO>();
		if (c != null ) {
    		if  (c.moveToFirst()) {
    			do { MannschaftVO mannschaftVO = new MannschaftVO(
    					c.getInt(c.getColumnIndex(MannschaftTbl.KLASSE_ID)),
    					c.getInt(c.getColumnIndex(MannschaftTbl.ID)), 
    					c.getString(c.getColumnIndex(MannschaftTbl.NAME)));
    				mannschaftListe.add(mannschaftVO);
    			}while (c.moveToNext());
    		} 
    	}

		return mannschaftListe;
	}
	
	/**
	 * Lädt die Klassen aus dem MannschaftTbl-Datensatz
	 * 
	 * @param klasseId KlasseId
	 * List<MannschaftVO> mannschaften
	 */
	public List<MannschaftVO> ladeAlleMannschaftListeVO(long klasseId) {	
		SQLiteDatabase d = mDb.getReadableDatabase();
		Cursor c = d.query(MannschaftTbl.TABLE_NAME, 
				MannschaftTbl.ALL_COLUMNS, 
				MannschaftTbl.KLASSE_ID + "=" + String.valueOf(klasseId), null, null, null, null);
		
		List<MannschaftVO> mannschaftListe = new ArrayList<MannschaftVO>();
		if (c != null ) {
    		if  (c.moveToFirst()) {
    			do { MannschaftVO mannschaftVO = new MannschaftVO(
    					c.getInt(c.getColumnIndex(MannschaftTbl.KLASSE_ID)),
    					c.getInt(c.getColumnIndex(MannschaftTbl.ID)), 
    					c.getString(c.getColumnIndex(MannschaftTbl.NAME)));
    				mannschaftListe.add(mannschaftVO);
    			}while (c.moveToNext());
    		} 
    	}

		return mannschaftListe;
	}

	/**
	 * Liefert alle Mannschaften mit einstellbarer Sortierung zurück.
	 * Es kann (optional) ein Filterkriterium angegeben werden. 
	 * Wenn der namensFilter definiert ist, werden nur Kontakte geliefert, deren NAME mit diesem Buchstaben beginnt.
	 * 
	 * @param sortierung Art der Sortierung
	 * @param namensFilter Anfangsbuchstaben (case sensitive) der zu suchenden Mannschaften.
	 * @return Cursor auf die Ergebnisliste.
	 */
	public Cursor ladeMannschaftListe(Sortierung sortierung, CharSequence namensFilter) {
		final SQLiteQueryBuilder mannschaftSuche = new SQLiteQueryBuilder();
		mannschaftSuche.setTables(MannschaftTbl.TABLE_NAME);
		String[] whereAttribs = null;
		if (namensFilter != null && namensFilter.length() > 0) {
			mannschaftSuche.appendWhere(MannschaftTbl.WHERE_NAME_LIKE);
			whereAttribs = new String[] { namensFilter + "%" };
		}

		return mannschaftSuche.query(mDb.getReadableDatabase(), MannschaftTbl.ALL_COLUMNS, null, whereAttribs, null, null,
				getMannschaftSortierung(sortierung));
	}

	/**
	 * Liefert alle Mannschaften zur KlassenId und mit einstellbarer Sortierung zurück.
	 * 
	 * @param sortierung Art der Sortierung
	 * @param namensFilter Anfangsbuchstaben (case sensitive) der zu suchenden Kontakte.
	 * @param klasseId KlassenId
	 * @return Cursor auf die Ergebnisliste.
	 */
	public Cursor ladeMannschaftZurKlasseListe(Sortierung sortierung, CharSequence namensFilter, long klasseId) {
		
		SQLiteDatabase d = mDb.getReadableDatabase();
		Cursor mannschaftCursor = d.query(MannschaftTbl.TABLE_NAME, 
				MannschaftTbl.ALL_COLUMNS, 
				MannschaftTbl.KLASSE_ID + "=" + String.valueOf(klasseId), null, null, null, null);
		
		return mannschaftCursor;
	}

	/**
	 * Liefert die Sortierung unter Berücksichtigung der Standard-Sortierung der Kontakttabelle.
	 * 
	 * @param sortierung Sortierung als enum.
	 * @return Sortierung als ORDER_BY kompatible Anweisung.
	 */
	private static String getMannschaftSortierung(Sortierung sortierung) {
		String sortiertNach = MannschaftTbl.DEFAULT_SORT_ORDER;
		switch (sortierung) {
		case NAME:
			sortiertNach = MannschaftTbl.NAME;
			break;
		case ID:
			sortiertNach = MannschaftTbl.ID;
			break;
		default:
			break;
		}
		return sortiertNach;
	}

	/**
	 * Lädt die Mannschaft aus dem MannschaftTbl-Datensatz, auf dem der Cursor gerade steht.
	 * 
	 * Der Cursor wird anschließend deaktiviert, da er im MannschaftSpeicher nur intern als "letzter Aufruf" aufgerufen wird.
	 * 
	 * @param c aktuelle Cursorposition != null
	 * @return MannschaftVO
	 */
	public MannschaftVO ladeGeoKontakt(Cursor c) {
		final MannschaftVO kontakt = new MannschaftVO();

		kontakt.key = c.getLong(c.getColumnIndex(MannschaftTbl.ID));
		kontakt.name = c.getString(c.getColumnIndex(MannschaftTbl.NAME));
		kontakt.mannschaft = c.getLong(c.getColumnIndex(MannschaftTbl.MANNSCHAFT));
		kontakt.klasseId = c.getLong(c.getColumnIndex(MannschaftTbl.KLASSE_ID));
		kontakt.vereinId = c.getLong(c.getColumnIndex(MannschaftTbl.VEREIN_ID));
		return kontakt;
	}

	/**
	 * Schliesst die zugrundeliegende Datenbank. Vor dem naechsten Zugriff muss oeffnen() aufgerufen werden.
	 */
	public void schliessen() {
		mDb.close();
		Log.d(TAG, "Datenbank kegelverwaltung geschlossen.");
	}

	/**
	 * Oeffnet die Datenbank, falls sie vorher mit schliessen() geschlossen wurde.
	 * Bei Bedarf wird das Schema angelegt bzw. aktualisiert.
	 */
	public void oeffnen() {
		mDb.getReadableDatabase();
		Log.d(TAG, "Datenbank kegelverwaltung geoeffnet.");
	}

	/**
	 * Oeffnet die Datenbank schreibbar, falls sie vorher mit schliessen() geschlossen wurde.
	 * Bei Bedarf wird das Schema angelegt bzw. aktualisiert.
	 */
	public void oeffnenSchreibzugriff() {
		mDb.getWritableDatabase();
		Log.d(TAG, "Datenbank kegelverwaltung schreibend geoeffnet.");
	}
	
	/**
	 * Gibt die Anzahl der Mannschaften in der Datenbank zurueck. <br>
	 * Performanter als Cursor::getCount.
	 * 
	 * @return Anzahl der Mannschaften.
	 */
	public int anzahlMannschaften() {
		final Cursor c = mDb.getReadableDatabase().rawQuery("select count(*) from " + MannschaftTbl.TABLE_NAME, null);
		if (c.moveToFirst() == false) {
			return 0;
		}
		return c.getInt(0);
	}

}
